﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using LastoRevival.Service.Contracts.Models;

namespace LastoRevival.Service.Implementations.Data.Sql.Converters
{
	public class ThreadsCreator
	{

		private ThreadCreator threadCreator;

		public ThreadsCreator(ThreadCreator threadCreator)
		{
			this.threadCreator = threadCreator;
		}

		public Threads Create(IEnumerable<DataRow> messageRows, int currentPage, int pageSize, int forumID, int threadCount)
		{
			var sortedMessages = ConvertAndSortMessages(forumID, messageRows);


			var threads = new Threads();
			
			// messages have already been sorted into threads, now we just need to sort the threads
			foreach (var messagesInThread in sortedMessages.Values)
			{
				var thread = threadCreator.Convert(messagesInThread);
				threads.Add(thread);
			}

			// calculate paging info
			threads.CurrentPage = currentPage;
			threads.TotalPages = (int)Math.Ceiling((double)threadCount / pageSize);

			return threads;
		}


		private Dictionary<int, List<DataRow>> ConvertAndSortMessages(int forumID, IEnumerable<DataRow> messageRows)
		{
			var sortedMessages = new Dictionary<int, List<DataRow>>();

			foreach (var row in messageRows)
			{
				var threadID = (int)row["thread_id"];

				// if there is no thread id, it means that it's a top level post, and the thread id is
				// the post ID
				threadID = threadID == 0 ? (int)row["ID"] : threadID;

				// either add a new entry in the dictionary, or insert this message
				// messages will always have a thread ID coming out of the database
				if (!sortedMessages.ContainsKey(threadID))
				{
					// add it
					sortedMessages.Add(threadID, new List<DataRow>());
				}

				// insert the message
				sortedMessages[threadID].Add(row);
			}

			return sortedMessages;
		}
	}

	public class ThreadCreator
	{

		public Thread Convert(IEnumerable<DataRow> messageRows)
		{
			// find the parent
			var parentRow = messageRows.FirstOrDefault(m => (int)m["thread_id"] == 0);

			var parent = ConvertPost(parentRow);

			var threadID = parent.PostID;

			var thread = new Thread();
			thread.TopMessage = CreateMessageThread(parent, messageRows);
			thread.Details = ConvertThreadDetails(parent, threadID, messageRows.Count());
			
			return thread;
		}



		private ThreadDetails ConvertThreadDetails(PreviewPostModel parentMessage, int threadID, int messageCount)
		{
			var details = new ThreadDetails
			{
				ForumID = parentMessage.ForumID,
				ThreadID = threadID,
				MessagesInThread = messageCount,
			};

			return details;
		}


		private PreviewPostModel ConvertPost(DataRow message)
		{
			var post = new PreviewPostModel();

			post.DatePosted = (DateTime)message["dateposted"];
			post.ForumID = (int)message["forumID"];
			post.PostID = (int)message["ID"];
			post.ParentPostID = (int)message["thread_parent"];
			// stick?
			post.Subject = string.Format("{0}", message["subject"]);
			post.Views = (int)message["threadviews"];
			post.GroupName = string.Format("{0}", message["groupname"]);
			post.Locked = (bool)message["Locked"];

			// figure out which username and id to use
			var userID = message["userID"] as int?;
			var userName = string.Format("{0}", message["username"]);

			if (userID == null)
			{
				userID = UserProfileDetails.AnonymousUserID;
				userName = "Anonymous";
			}

			post.UserID = userID.Value;
			post.UserName = userName;
			post.HasText = !string.IsNullOrEmpty(string.Format("{0}", message["body"]));

			return post;
		}

		private MessageThread CreateMessageThread(PreviewPostModel currentPost, IEnumerable<DataRow> messageRows)
		{
			var currentMessage = new MessageThread();

			currentMessage.PostDetails = currentPost;
			currentMessage.ChildPosts = new List<MessageThread>();

			// child posts are all those which have this post as a parentID
			var childRows = messageRows.Where(c => (int)c["thread_parent"] == currentPost.PostID);

			foreach (var row in childRows)
			{
				var child = ConvertPost(row);
				var childMessage = CreateMessageThread(child, messageRows);
				currentMessage.ChildPosts.Add(childMessage);
			}

			// set parent
			currentMessage.ParentPost = null;

			return currentMessage;
		}
	}
}
